package com.alibaba.travel.member.service.impl;

import com.alibaba.travel.common.constant.RedisConstants;
import com.alibaba.travel.common.utils.*;
import com.alibaba.travel.member.Utils.UserHolder;
import com.alibaba.travel.member.dto.LoginPhoneInfo;
import com.alibaba.travel.member.dto.LoginUsernameInfo;
import com.alibaba.travel.member.dto.RegisterInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.alibaba.travel.member.dao.UserDao;
import com.alibaba.travel.member.entity.UserEntity;
import com.alibaba.travel.member.service.UserService;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;


@Slf4j
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 用户注册接口
     * @param registerInfo
     * @return
     */
    @Override
    public R register(RegisterInfo registerInfo) {
        //校验info
        if(ObjectUtils.isEmpty(registerInfo)){
            return R.error(400,"不能传入空参！");
        }
        String username = registerInfo.getUsername();
        String password = registerInfo.getPassword();

        boolean isStandard=judgeInfo(username,password);

        if(!isStandard){
            return R.error(400,"输入的用户名或者密码不合法");
        }
        //用户注册业务逻辑
        //1` 查询数据库中是否有相同username的用户
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getUserName,registerInfo.getUsername());
        UserEntity userOne = this.baseMapper.selectOne(wrapper);
        if(!ObjectUtils.isEmpty(userOne)){
            //1`1 如果有，返回错误信息
            return R.error(400,"用户名重复！");
        }
        //2` 没有，更新insert数据库
        userOne=new UserEntity();
        userOne.setUserName(username);
        userOne.setNickName(username);
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        userOne.setPassword(password);
        userOne.setUpdateTime(new Date());
        baseMapper.insert(userOne);
        log.info("成功插入一条数据：{}",userOne);
        //3` 返回成功信息！


        return R.ok("注册成功！").setData(userOne);
    }

    /**
     * 用户账号密码登录接口
     * @param loginUsernameInfo
     * @return
     */
    @Override
    public R loginWithUsername(LoginUsernameInfo loginUsernameInfo) {
        //校验loginInfo
        if(ObjectUtils.isEmpty(loginUsernameInfo)) {
            return R.error(400, "不能传入空参！");
        }

        //用户登录业务逻辑
        String username = loginUsernameInfo.getUsername();
        String password = loginUsernameInfo.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if(StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
            return R.error("参数为空!");
        }
        //1. 查询数据库是否有用户名为username的用户
        LambdaQueryWrapper<UserEntity>queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUserName, username);
        UserEntity userOne = this.baseMapper.selectOne(queryWrapper);
        //1.1 如果没有则返回错误信息
        if (userOne == null){
            return R.error(400,"账号不存在");
        }
        //2. 如果有，判断密码是否输入正确
        if (!password.equals(userOne.getPassword())){
            return R.error(400, "密码错误");
        }
        try {
            //3. 密码正确则将用户信息存入redis,key为id
            Long id = userOne.getId();
            String json = objectMapper.writeValueAsString(userOne);
            stringRedisTemplate.opsForValue().set(RedisConstants.USER_LOGIN_KEY+id,json);

            //4. 将用户id存入token
            String jwt = JwtUtil.createJWT(id.toString());
            return R.ok().put("jwt",jwt);
        } catch (JsonProcessingException e) {
            return R.error("未知异常！");
        }

    }

    /**
     * 用户手机号登录接口
     * @param loginPhoneInfo
     * @return
     */
    @Override
    public R loginWithPhone(LoginPhoneInfo loginPhoneInfo) {
        if(ObjectUtils.isEmpty(loginPhoneInfo)){
            return R.error("参数不能为空！");
        }
        String phone = loginPhoneInfo.getPhone();
        //获取验证码，与手机号
        String captcha = loginPhoneInfo.getCaptcha();

        if(StringUtils.isEmpty(phone)||StringUtils.isEmpty(captcha)){
            return R.error("phone与验证码不能为空！");
        }

        //验证对应手机号获得的验证码是否匹配。
        String confirmCap = (String) stringRedisTemplate.opsForValue().get(RedisConstants.USER_LOGIN_CODE_KEY + phone);
        if(StringUtils.isEmpty(confirmCap)){
            return R.error("验证码过期！");
        }
        if(!confirmCap.equals(captcha)){
            return R.error("验证码输入错误!");
        }
        //手机和验证码正确。
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getPhone,phone);
        UserEntity user = baseMapper.selectOne(wrapper);
        if(ObjectUtils.isEmpty(user)){
            return R.error("手机号未注册，请先注册!");
        }

        //查到对应用户,将用户信息存入缓存当中
        Long id = user.getId();
        try {
            String objectJson = objectMapper.writeValueAsString(user);
            stringRedisTemplate.opsForValue().set(RedisConstants.USER_LOGIN_KEY+id,objectJson);
            //生成jwt，存入id信息。
            String jwt = JwtUtil.createJWT(id.toString());
            return R.ok().put("jwt",jwt);
        } catch (JsonProcessingException e) {
            return R.error().setData(e.getMessage());
         }

    }


    @Override
    public R sendMsg(LoginPhoneInfo loginPhoneInfo) {
        //校验
        if(ObjectUtils.isEmpty(loginPhoneInfo)){
            return R.error("参数为空!");
        }
        String phone = loginPhoneInfo.getPhone();

        if (StringUtils.isNotEmpty(phone)){
            String captcha = ValidateCodeUtils.generateValidateCode(6).toString();
            log.info("captcha={}", captcha);
            stringRedisTemplate.opsForValue().set(RedisConstants.USER_LOGIN_CODE_KEY+phone, captcha
                    ,RedisConstants.USER_LOGIN_CODE_TTL,TimeUnit.MINUTES);
            return R.ok("手机验证码发送成功");
        }
        return R.error("短信发送失败");
    }


    /**
     * 用户注销
     * @return
     */
    @Override
    public R logout() {
        //清楚redis缓存即可
        Boolean delete = stringRedisTemplate.delete(RedisConstants.USER_LOGIN_KEY + UserHolder.getUser().getId());
        if(!delete){
            //TODO  未知错误
            return R.error("未知错误信息!");
        }

        return R.ok("退出成功!");
    }

    /**
     * 更新redis和数据库
     * @param user
     * @return
     */
    @Override
    public R updateDataAndCache(UserEntity user) {
        //校验处理
        if(ObjectUtils.isEmpty(user)){
            return R.error("参数不能为空!");
        }
        //        更新redis和数据库
        // 防止高并发，先处理数据库，在更新缓存
        try {
            baseMapper.updateById(user);
            String jsonObj = objectMapper.writeValueAsString(user);
            stringRedisTemplate.opsForValue().set(RedisConstants.USER_LOGIN_KEY+user.getId(),jsonObj
                    ,RedisConstants.USER_LOGIN_TTL,TimeUnit.HOURS);
            return R.ok("更新成功!");
        } catch (JsonProcessingException e) {
            return R.error(e.getMessage());
        }
    }

    /**
     * 判断输入数据是否合法
     * @param username
     * @param password
     * @return
     */
    @Override
    public boolean judgeInfo(String username, String password) {
//        if(username.matches("/^[\\w\\u4e00-\\u9fa5]{4,16}$/")) return false;
//        if(password.matches("/^.*(?=.{6,16})(?=.*\\d)(?=.*[A-Za-z])(?=.*[!@#$%^&*?\\.]).*$/"))
//            return false;
        return true;
    }



}